﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.IO;
using System.Web.Mvc;
using Microsoft.Reporting;
using Microsoft.Reporting.WebForms;
using System.Reflection;

namespace SIBI.Helpers
{
    public static class ReportHelper
    {
        //BienInformaticoId,cubf,nanf,nena,dfact,diniar,dfinar,cedo,ctipb,csoc,cdiv,cusr,cmar,cmod,ccla,cloc,ceco
        public static Type RepItemGetTipo(string tcnombre)
        {
            Type Tipo;
            switch (tcnombre.ToUpper()[0])
            {
                case 'I': Tipo = typeof(Int32); break;
                case 'N': Tipo = typeof(Decimal); break;
                case 'D': Tipo = typeof(DateTime); break;
                default: Tipo = typeof(string); break;
            }
            return Tipo;
        }
        public static bool IsTypeNullable(Type TypeToTest)
        {
            // Abort if no type supplied
            if (TypeToTest == null)
                return false;
            // If this is not a value type, it is a reference type, so it is automatically nullable
            //  (NOTE: All forms of Nullable<T> are value types)
            if (!TypeToTest.IsValueType)
                return true;
            // Report whether TypeToTest is a form of the Nullable<> type
            return TypeToTest.IsGenericType && TypeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
        }

        public class RepDataSet<T> : DataTable 
        {
            public RepDataSet(string tcnombre, string tccampos)
            {
                this.TableName = tcnombre;
                NewDataStructForRep(this, tcnombre, tccampos);
            }
            public RepDataSet(string tcnombre)
            {
                this.TableName = tcnombre;
                Type Tipo;
                foreach (PropertyInfo pinf in typeof(T).GetProperties( ))
                {
                    Tipo = pinf.PropertyType;
                    if (Tipo.Equals(typeof(Nullable<DateTime>))) Tipo = typeof(DateTime);
                    if (Tipo.Equals(typeof(Nullable<int>))) Tipo = typeof(int);
                    if (Tipo.Equals(typeof(Nullable<Decimal>))) Tipo = typeof(Decimal);
                    if (Tipo.Equals(typeof(Nullable<double>))) Tipo = typeof(double);
                    this.Columns.Add(pinf.Name, Tipo);
                }
            }
        }
        public class TipoRepEstructura
        {
            public object[] ToArray<T>()
            {
                List<object> list = new List<object>();
                foreach (PropertyInfo pinf in typeof(T).GetProperties())
                {
                    list.Add( pinf.GetValue(this, null));
                }
                return list.ToArray<object>();
            }
            public void CopyRow<T>(System.Data.DataTable dtt, T tobj)
            {
                System.Data.DataRow drt = dtt.Rows.Add();
                foreach (PropertyInfo pinf in typeof(T).GetProperties())
                {
                    drt.SetField<object>(pinf.Name, pinf.GetValue(tobj, null));
                }
            }
            public void CopyRow<T>(System.Data.DataTable dtt)
            {
                System.Data.DataRow drt = dtt.Rows.Add();
                foreach (PropertyInfo pinf in typeof(T).GetProperties())
                {
                    drt.SetField<object>(pinf.Name, pinf.GetValue(this, null));
                }
            }
        }
        public static DataTable NewDataStructForRep(string tcnombre, string tccampos, params Type[] Typos)
        {
            DataTable dt = new DataTable(tcnombre);
            string[] campos = tccampos.Split(',');
            for (int ln0 = 0; ln0 < campos.Length; ln0++)
            {
                dt.Columns.Add(campos[ln0], ln0 < Typos.Length ? Typos[ln0] : RepItemGetTipo(campos[ln0]));
            }
            return dt;
        }//NewDataStructForRep

     
        public static void NewDataStructForRep(DataTable dt, string tcnombre, string tccampos, params Type[] Typos)
        {
            string[] campos = tccampos.Split(',');
            for (int ln0 = 0; ln0 < campos.Length; ln0++)
            {
                dt.Columns.Add(campos[ln0], ln0 < Typos.Length ? Typos[ln0] : RepItemGetTipo(campos[ln0]));
            }
        }//NewDataStructForRep

        public static void SetReportDatasources(object toReporte,
                string tcnomDS,
                params Object[] tolista)
        {

            ReportViewer torep = (toReporte as ReportViewer);
            torep.ProcessingMode = ProcessingMode.Local;

            if (torep != null)
            {
                torep.LocalReport.DataSources.Clear();
                string[] campos = tcnomDS.Split(',');
                for (int ln0 = 1; ln0 <= tolista.Length; ln0++)
                {
                    ReportDataSource ds1 = new ReportDataSource(campos[ln0 - 1], tolista[ln0 - 1]);
                    torep.LocalReport.DataSources.Add(ds1);
                }
            }
        }//SetReportDatasources

        public static void SetReportParams(object toReporte,
                string tcnomParams,
                params Object[] tolista)
        {
            ReportViewer torep = (toReporte as ReportViewer);
            if (torep != null)
            {
                List<ReportParameter> parameters = new List<ReportParameter>();
                string[] paramets = tcnomParams.Split(',');
                for (int ln0 = 1; ln0 <= tolista.Length; ln0++)
                {
                    parameters.Add(new ReportParameter(paramets[ln0 - 1], (tolista[ln0 - 1]==null)?"":tolista[ln0 - 1].ToString()));
                }
            }
        }//SetReportParams

        public static void SetReportParamsYPath(object toReporte,
                string reportPath,
                string tcnomParams,
                params Object[] tolista)
        {
            ReportViewer torep = (toReporte as ReportViewer);
            if (torep != null)
            {
                List<ReportParameter> parameters = new List<ReportParameter>();
                string[] paramets = tcnomParams.Split(',');
                for (int ln0 = 1; ln0 <= tolista.Length; ln0++)
                {
                    parameters.Add(new ReportParameter(paramets[ln0 - 1], tolista[ln0 - 1].ToString()));
                }
                torep.LocalReport.ReportPath = reportPath;
                torep.LocalReport.SetParameters(parameters);
                torep.LocalReport.Refresh();

            }
        }
        public static void SetReportData(object toReporte,
            string reportPath,
            string tcnomDS,
            Object[] tolistaDs,
            string tcnomParams,
            params Object[] tolista)
        {
            ReportViewer torep = (toReporte as ReportViewer);
            if (torep != null)
            {
                torep.ProcessingMode = ProcessingMode.Local;
                torep.LocalReport.ReportPath = HttpContext.Current.Server.MapPath( reportPath);
                torep.LocalReport.DataSources.Clear();
                string[] campos = tcnomDS.Split(',');
                for (int ln0 = 1; ln0 <= tolistaDs.Length; ln0++)
                {
                    ReportDataSource ds1 = new ReportDataSource(campos[ln0 - 1], tolistaDs[ln0 - 1]);
                    torep.LocalReport.DataSources.Add(ds1);
                }
                if (tcnomParams != null)
                {
                    List<ReportParameter> parameters = new List<ReportParameter>();
                    string[] paramets = tcnomParams.Split(',');
                    for (int ln0 = 1; ln0 <= tolista.Length; ln0++)
                    {
                        parameters.Add(new ReportParameter(paramets[ln0 - 1], tolista[ln0 - 1].ToString()));
                    }
                    torep.LocalReport.SetParameters(parameters);
                }
                torep.LocalReport.Refresh();

            }
        }//SetReportParamsYPath
        /// <summary>
        /// 
        /// </summary>
        /// <param name="toReporte"></param>
        /// <param name="reportPath"></param>
        /// <param name="tcnomDS"></param>
        /// <param name="tolistaDs"></param>
        /// <param name="tcnomParams"></param>
        /// <param name="tolista"></param>
        /// <returns></returns>
        public static string GetReportFile(object toReporte,
            string reportPath,
            string tcnomDS,
            Object[] tolistaDs,
            string tcnomParams,
            params Object[] tolista)
        {
            string ls0 = "";

            DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(HttpContext.Current.Server.MapPath("/TMP/Inicio.pdf")));
            foreach (FileInfo fi in di.GetFiles("+.pdf"))
            {
                try
                {
                    fi.Delete();
                }
                catch { }
            }
            FileStream lfile = di.CreateFileWithUniqueName(Path.GetFileNameWithoutExtension(reportPath) + ".pdf");
            if (lfile != null)
            {
                try
                {
                    ReportViewer torep = (toReporte as ReportViewer);
                    if (torep != null)
                    {
                        torep.ProcessingMode = ProcessingMode.Local;
                        torep.LocalReport.ReportPath = HttpContext.Current.Server.MapPath(reportPath);
                        torep.LocalReport.DataSources.Clear();
                        string[] campos = tcnomDS.Split(',');
                        for (int ln0 = 1; ln0 <= tolistaDs.Length; ln0++)
                        {
                            ReportDataSource ds1 = new ReportDataSource(campos[ln0 - 1], tolistaDs[ln0 - 1]);
                            torep.LocalReport.DataSources.Add(ds1);
                        }
                        if (tcnomParams != null)
                        {
                            List<ReportParameter> parameters = new List<ReportParameter>();
                            string[] paramets = tcnomParams.Split(',');
                            for (int ln0 = 1; ln0 <= tolista.Length; ln0++)
                            {
                                parameters.Add(new ReportParameter(paramets[ln0 - 1], tolista[ln0 - 1].ToString()));
                            }
                            torep.LocalReport.SetParameters(parameters);
                        }
                        torep.LocalReport.Refresh();
                        string deviceInfo =
                 "<DeviceInfo>" +
                 "  <OutputFormat>EMF</OutputFormat>" +
                 "  <PageWidth>8.5in</PageWidth>" +
                 "  <PageHeight>11in</PageHeight>" +
                 "  <MarginTop>0.12in</MarginTop>" +
                 "  <MarginLeft>0.12in</MarginLeft>" +
                 "  <MarginRight>0.12in</MarginRight>" +
                 "  <MarginBottom>0.12in</MarginBottom>" +
                 "</DeviceInfo>";
                        Warning[] warnings;
                        string[] streamids;
                        string mimeType;
                        string encoding;
                        string extension;
                        byte[] bytes = torep.LocalReport.Render("PDF", deviceInfo, out mimeType, out encoding, out extension, out streamids, out warnings);
                        lfile.Write(bytes, 0, bytes.Length);
                        ls0 = "/TMP/" + Path.GetFileName(lfile.Name);
                        lfile.Close();
                    }
                }
                catch (IOException ioe)
                {
                    //handle 
                    ls0 = "*Err ";
                }
                catch (Exception fp) //FileIOPermission 
                {
                    ls0 = "*Err ";
                    //handle
                }
            }
            return ls0;
        }//GetReportFile
    }


    public static class ReporExtension
    {
        public static MvcHtmlString  MonReport(this HtmlHelper helper, string reporte, string anchoVentana)
        {
            return MvcHtmlString.Create(String.Format(@"
                <script type='text/javascript'>
    
                    function processingComplete() {{
                        $('.cargador').css('display', 'none');
                    }}
                    $(document).ready(function () {{
                        $('#imprimeReporte').modal({{ opacity: 10,
                            minHeight: 580, maxHeight: 590, minWidth: '{1}'=='auto'?$(window).width()-50:{1}, maxWidth: '{1}'=='auto'?$(window).width()-50:{1},
                            autoResize: true, modal: true, autoPosition: true, close: true, overlayClose: true,
                            closeHTML: ""<a class='modalCloseImg' title='Cerrar' ></a>""
                        }});
                        $('#lnktitulo').click(function () {{ $('document').trigger('ready'); }});
                    }});

                </script>
                <div id='imprimeReporte' style='position:relative; background: white; overflow:auto; display:none;' align='center'>
                    <div class='cargador'><img src='../../Content/images/cargando.gif' alt='loading' />
                        <h1>Espere mientras carga.....</h1>
                    </div>
                    <iframe id='framereporte' scrolling='auto' src='{0}' frameborder='0' height='590px' width='100%' onload='processingComplete()'></iframe>
                </div>
                ",
                reporte, anchoVentana));
        }
        public static MvcHtmlString MonRep(this HtmlHelper helper, string nombrerep)
        {
            var buildMain = new System.Text.StringBuilder();
            var buildScript = new System.Text.StringBuilder();
            ReportViewer torep = new ReportViewer();
            System.Web.UI.ScriptManager objscript = new System.Web.UI.ScriptManager();
            DataTable tblReporte = ReportHelper.NewDataStructForRep("Reporte", "repNombre", typeof(String));
            DataTable tblBienes = ReportHelper.NewDataStructForRep("Bienes", "cBienInformaticoId,cubf,nanf,nena,dfact,diniar,dfinar,cedo,ctipb,csoc,cdiv,cusr,cmar,cmod,ccla,cloc,ceco");

            tblReporte.Rows.Add(new object[] {"Reporte de Bienes Informáticos" });
            tblBienes.Rows.Add(new object[] { "cBienInformaticoId", "cubf", 1, 2, DateTime.Now, DateTime.Now, DateTime.Now, "cedo", "ctipb", "csoc", "cdiv", "cusr", "cmar", "cmod", "ccla", "cloc", "ceco" });
            ReportHelper.SetReportDatasources(torep, "Reporte,Bienes",
                    new object[] { 
                    // Campos Adicionales de Impresion
                    tblReporte,
                    // Estructura de Bienes Informáticos
                    tblBienes
                });
            ReportHelper.SetReportParamsYPath(torep, "REP/REP_Bienes.rdl", "repNombre",
                      "Reporte NEcesitado");

            objscript.RenderControl(new System.Web.UI.HtmlTextWriter(new System.IO.StringWriter(buildScript)));
            torep.RenderControl(new System.Web.UI.HtmlTextWriter(new System.IO.StringWriter(buildMain)));
            return MvcHtmlString.Create(buildScript.ToString()+buildMain.ToString());
        }

        
    }
    public static class DirectoryInfoHelpers
    {
        public static FileStream CreateFileWithUniqueName(this DirectoryInfo dir, string rootName)
        {
            FileStream fs = dir.TryCreateFile(rootName); // try the simple name first

            // if that didn't work, try mixing in the date/time
            if (fs == null)
            {
                string date = DateTime.Now.ToString("yyyy-MM-ddTHHmmss");
                string stem = Path.GetFileNameWithoutExtension(rootName);
                string ext = Path.GetExtension(rootName) ?? ".dat";

                ext = ext.Substring(1);

                string fn = string.Format("{0}.{1}.{2}", stem, date, ext);
                fs = dir.TryCreateFile(fn);

                // if mixing in the date/time didn't work, try a sequential search
                if (fs == null)
                {
                    int seq = 0;
                    do
                    {
                        fn = string.Format("{0}.{1}.{2:0000}.{3}", stem, date, ++seq, ext);
                        fs = dir.TryCreateFile(fn);
                    } while (fs == null);
                }

            }

            return fs;
        }

        private static FileStream TryCreateFile(this DirectoryInfo dir, string fileName)
        {
            FileStream fs = null;
            try
            {
                string fqn = Path.Combine(dir.FullName, fileName);
                fs = new FileStream(fqn, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None);
            }
            catch (Exception)
            {
                fs = null;
            }
            return fs;
        }

    }
}